tg-me.com/javaproglib/6552
Last Update:
Проверять данные вручную через if-ы — больно, скучно и не масштабируется.
Bean Validation (javax.validation) позволяет валидировать красиво и декларативно, не превращая код в болото.
implementation("org.springframework.boot:spring-boot-starter-validation")
ИЛИ
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
public class UserRequest {
@NotBlank(message = "Имя не должно быть пустым")
private String name;
@Email(message = "Некорректный email")
private String email;
@Min(value = 18, message = "Возраст должен быть 18+")
private int age;
// геттеры и сеттеры
}
@PostMapping("/users")
public ResponseEntity<?> createUser(@Valid @RequestBody UserRequest request) {
userService.save(request);
return ResponseEntity.ok().build();
}
Без @Valid перед DTO ничего не сработает.
@RestControllerAdvice
public class ExceptionHandlerController {
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<?> handleValidationErrors(MethodArgumentNotValidException ex) {
List<String> errors = ex.getBindingResult().getFieldErrors().stream()
.map(err -> err.getField() + ": " + err.getDefaultMessage())
.toList();
return ResponseEntity.badRequest().body(errors);
}
}
Теперь ошибки приходят красиво и читаемо в JSON.
Если нужно что-то особенное — например, проверка страны:
@Constraint(validatedBy = CountryValidator.class)
@Target({ ElementType.FIELD })
@Retention(RetentionPolicy.RUNTIME)
public @interface ValidCountry {
String message() default "Страна не поддерживается";
}
public class CountryValidator implements ConstraintValidator<ValidCountry, String> {
private final List<String> allowed = List.of("RU", "US", "DE");
public boolean isValid(String value, ConstraintValidatorContext ctx) {
return allowed.contains(value);
}
}